use tokio::sync::{mpsc, oneshot};

use crate::types::channel;

use super::{iblog_client, rauth_client};

pub struct Client {
    rauth_client: rauth_client::Client,
    iblog_client: iblog_client::Client,
}

impl Client {
    async fn new() -> Self {
        Client {
            rauth_client: rauth_client::Client::new().await,
            iblog_client: iblog_client::Client::new().await,
        }
    }
}

async fn rauth_grpc_client_start(
    rauth_client: &mut rauth_client::Client,
    mut rx_channel: mpsc::Receiver<(channel::Request, oneshot::Sender<channel::Response>)>,
) {
    loop {
        let (req, rsp_ch): (channel::Request, oneshot::Sender<channel::Response>) =
            rx_channel.recv().await.unwrap();

            println!("2222");

        match req {
            // Rauth rpc request
            channel::Request::UserRegister(r) => rauth_client.user_register(r, rsp_ch).await,
            channel::Request::UserLogin(r) => rauth_client.user_login(r, rsp_ch).await,
            channel::Request::UserChangePassword(r) => {
                rauth_client.user_change_password(r, rsp_ch).await
            }
            channel::Request::UserUpdate(r) => rauth_client.user_update(r, rsp_ch).await,
            channel::Request::UserGet(r) => rauth_client.user_get(r, rsp_ch).await,
            channel::Request::UserDelete(r) => rauth_client.user_delete(r, rsp_ch).await,

            _ => rsp_ch
                .send(channel::Response::Error(
                    "Invalid request type to rauth grpc client".to_string(),
                ))
                .expect("failed to send channel response by rauth grcp client"),
        }
    }
}

async fn iblog_grpc_client_start(
    iblog_client: &mut iblog_client::Client,
    mut rx_channel: mpsc::Receiver<(channel::Request, oneshot::Sender<channel::Response>)>,
) {
    loop {
        let (req, rsp_ch): (channel::Request, oneshot::Sender<channel::Response>) =
            rx_channel.recv().await.unwrap();

        match req {
            // Iblog rpc request
            channel::Request::BlogAdd(r) => iblog_client.blog_add(r, rsp_ch).await,
            channel::Request::BlogUpdate(r) => iblog_client.blog_update(r, rsp_ch).await,
            channel::Request::BlogGet(r) => iblog_client.blog_get(r, rsp_ch).await,
            channel::Request::BlogsGet(r) => iblog_client.blogs_get(r, rsp_ch).await,
            channel::Request::BlogDelete(r) => iblog_client.blog_delete(r, rsp_ch).await,
            channel::Request::BlogViewInc(r) => iblog_client.blog_view_inc(r, rsp_ch).await,
            channel::Request::BlogStarInc(r) => iblog_client.blog_star_inc(r, rsp_ch).await,
            channel::Request::BlogStarDec(r) => iblog_client.blog_star_dec(r, rsp_ch).await,

            channel::Request::IdeaAdd(r) => iblog_client.idea_add(r, rsp_ch).await,
            channel::Request::IdeaUpdate(r) => iblog_client.idea_update(r, rsp_ch).await,
            channel::Request::IdeaGet(r) => iblog_client.idea_get(r, rsp_ch).await,
            channel::Request::IdeasGet(r) => iblog_client.ideas_get(r, rsp_ch).await,
            channel::Request::IdeaDelete(r) => iblog_client.idea_delete(r, rsp_ch).await,
            channel::Request::IdeaViewInc(r) => iblog_client.idea_view_inc(r, rsp_ch).await,
            channel::Request::IdeaStarInc(r) => iblog_client.idea_star_inc(r, rsp_ch).await,
            channel::Request::IdeaStarDec(r) => iblog_client.idea_star_dec(r, rsp_ch).await,

            _ => rsp_ch
                .send(channel::Response::Error(
                    "Invalid request type to iblog grpc client".to_string(),
                ))
                .expect("failed to send channel response by iblog grcp client"),
        }
    }
}

// Cant not use lock to lock client, because lock does not match send trait.
// So use mpsc channel to handle it, other modules tx and grpc-client rx.
pub async fn start(
    rauth_rx_channel: mpsc::Receiver<(channel::Request, oneshot::Sender<channel::Response>)>,
    iblog_rx_channel: mpsc::Receiver<(channel::Request, oneshot::Sender<channel::Response>)>,
) {
    let mut client = Client::new().await;

    let _ = tokio::join!(
        rauth_grpc_client_start(&mut client.rauth_client, rauth_rx_channel),
        iblog_grpc_client_start(&mut client.iblog_client, iblog_rx_channel),
    );
}
